# -*- coding: utf-8 -*-
import KBEngine
import IKernel
import MsgDef
import RoomDef
import ErrorCodeDef
import ConstDef
import HallDef
import StateDef
import time
import random

class HallModule:
	def __init__(self):
		# key   roomID
		# value entity
		self.emptyRooms = {}
		self.playRooms = {}
		self.matchPlayers = {}
		self.hallEntityID = 0

		self.newPlayerPos = [0,0,0]

	def init(self, isReload):
		IKernel.Instance().registerFunc("HallModule.onBaseMsg", self.onBaseMsg)
		IKernel.Instance().registerFunc("HallModule.onAccountInit", self.onAccountInit)
		IKernel.Instance().registerFunc("HallModule.onClientMsg", self.onClientMsg)
		IKernel.Instance().registerFunc("HallModule.hbCheckRoomNum", self.hbCheckRoomNum)
		IKernel.Instance().registerFunc("HallModule.onTeleportSuccess", self.onTeleportSuccess)
		IKernel.Instance().registerFunc("HallModule.onAccountEnterHall", self.onAccountEnterHall)

		IKernel.Instance().addIntMsgCallback(MsgDef.BASE2CELL_HALL_MSG, "HallModule.onBaseMsg")
		IKernel.Instance().addIntMsgCallback(MsgDef.CLIENT2CELL_HALL_MSG, "HallModule.onClientMsg")

		IKernel.Instance().addEventCallback("Hall", "onTeleportSuccess", "HallModule.onTeleportSuccess")

		IKernel.Instance().addEventCallback("Account", "onEnterSpace", "HallModule.onAccountEnterHall")
		IKernel.Instance().addEventCallback("Account", "init", "HallModule.onAccountInit")

	def end(self):
		pass

	def hbCheckRoomNum(self, entityID, alreadyTickCount, interval):
		"""
		5秒一次的检测，如果5秒中，还没有回复，说明连接有问题，在一次请求
		"""
		if len(self.emptyRooms) <= 0:
			args = []
			args.append(MsgDef.CELL2BASE_HALL_MSG)
			args.append(RoomDef.SUBMSG_CREATE_EMPTY_ROOM)
			IKernel.Instance().sendBaseMsg(self.hallEntityID, self.hallEntityID, args)
			return

		# 多余的空房间，需要删除
		while len(self.emptyRooms) > RoomDef.OnceCreateEmptyRoomNum:
			roomKV = self.emptyRooms.popitem()
			roomID = roomKV[0]
			roomEntity = roomKV[1]
			roomEntity.destroy()

	def onTeleportSuccess(self, eventType, eventName, senderEntityID, receiverEntityID, args):
		playerEntityID = receiverEntityID
		self.setNewPlayerPos(playerEntityID)

	def onAccountInit(self, eventType, eventName, senderEntityID, receiverEntityID, args):
		playerEntity = KBEngine.entities.get(receiverEntityID)
		if playerEntity.uid == 0:
			playerEntity.uid = KBEngine.genUUID64()

		KBEngine.globalData[playerEntity.uid] = receiverEntityID

	def onAccountEnterHall(self, eventType, eventName, senderEntityID, receiverEntityID, args):
		playerEntityID = receiverEntityID
		playerEntity = KBEngine.entities.get(playerEntityID)
		roomEntity = KBEngine.entities.get(self.hallEntityID)
		if playerEntity.spaceID != roomEntity.spaceID:
			# 进入的不是大厅空间
			return

		self.setNewPlayerPos(playerEntityID)

		msg = []
		msg.append(MsgDef.CELL2CLIENT_HALL_MSG)
		msg.append(HallDef.SUBMSG_ENTER)
		IKernel.Instance().sendClientMsg(playerEntityID, msg)

	def setNewPlayerPos(self, playerEntityID):
		playerEntity = KBEngine.entities.get(playerEntityID)

		randIndx = random.randint(0, len(self.newPlayerPos) - 1)
		self.newPlayerPos[randIndx] += 1

		#玩家退出
		playerEntity.curState = StateDef.Player.Idle
		playerEntity.orgViewRadius = playerEntity.getViewRadius()
		playerEntity.setViewRadius(0,5)
		playerEntity.position.x = self.newPlayerPos[0]
		playerEntity.position.y = self.newPlayerPos[1]
		playerEntity.position.z = self.newPlayerPos[2]

	def onBaseMsg(self, senderEntityID, receiverEntityID, args):
		dispatcher = {
			RoomDef.SUBMSG_CREATE_EMPTY_ROOM : self.createEmptyRoom,
			RoomDef.SUBMSG_CREATE_HALL_SUCCESS : self.createHallSuccess,
		}
		submsg = args[1]
		funcAddr = dispatcher.get(submsg)
		if funcAddr == None:
			return
		funcAddr(senderEntityID, receiverEntityID, args)

	def createEmptyRoom(self, senderEntityID, receiverEntityID, args):
		roomEntityID = senderEntityID
		roomEntity = KBEngine.entities[roomEntityID]
		self.emptyRooms[roomEntity.roomID] = roomEntity

	def createHallSuccess(self, senderEntityID, receiverEntityID, args):
		self.hallEntityID = senderEntityID
		IKernel.Instance().addHeartbeat(self.hallEntityID, "HallModule.hbCheckRoomNum", 5000, -1)

	def onClientMsg(self, senderEntityID, receiverEntityID, args):
		dispatcher = {
			RoomDef.SUBMSG_CREATE_ROOM : self.createRoom,
			RoomDef.SUBMSG_MATCH_ROOM : self.matchRoom,
			RoomDef.SUBMSG_EXIT_ROOM : self.exitRoom,
			RoomDef.SUBMSG_ENTER_ROOM : self.enterRoom,
			RoomDef.SUBMSG_SETUP_HEAD_ICON : self.setupHeadIcon,
		}
		submsg = args[1]
		funcAddr = dispatcher.get(submsg)
		if funcAddr == None:
			return
		funcAddr(receiverEntityID, args)

	def createRoom(self, receiverEntityID, args):
		if len(self.emptyRooms) <= 0:
			msg = []
			msg.append(MsgDef.CELL2CLIENT_HALL_MSG)
			msg.append(RoomDef.SUBMSG_CREATE_ROOM)
			msg.append(ErrorCodeDef.NoEmptyRoom)
			IKernel.Instance().sendClientMsg(receiverEntityID, msg)
			return

		playerEntity = KBEngine.entities.get(receiverEntityID)
		if playerEntity.curState != StateDef.Player.Idle or playerEntity.roomID != 0 :
			msg = []
			msg.append(MsgDef.CELL2CLIENT_HALL_MSG)
			msg.append(RoomDef.SUBMSG_CREATE_ROOM)
			msg.append(ErrorCodeDef.NoInIdle)
			IKernel.Instance().sendClientMsg(receiverEntityID, msg)
			return

		roomKV = self.emptyRooms.popitem()
		roomID = roomKV[0]
		roomEntity = roomKV[1]
		self.playRooms[roomID] = roomEntity

		playerEntity.roomID = roomID
		playerEntity.curState = StateDef.Player.RoomNoPlayWait
		playerEntity.teleport(roomEntity, (0, 0, 0), (0, 0, 0))

		msg = []
		msg.append(MsgDef.CELL2CLIENT_HALL_MSG)
		msg.append(RoomDef.SUBMSG_CREATE_ROOM)
		msg.append(ErrorCodeDef.No)
		IKernel.Instance().sendClientMsg(receiverEntityID, msg)

	def matchRoom(self, receiverEntityID, args):
		playerEntity = KBEngine.entities.get(receiverEntityID)
		if playerEntity.curState != StateDef.Player.Idle or playerEntity.roomID != 0 :
			msg = []
			msg.append(MsgDef.CELL2CLIENT_HALL_MSG)
			msg.append(RoomDef.SUBMSG_MATCH_ROOM)
			msg.append(ErrorCodeDef.NoInIdle)
			IKernel.Instance().sendClientMsg(receiverEntityID, msg)
			return

		curMsec = int(time.time() * 1000)
		while self.matchPlayers.get(curMsec) != None:
			curMsec += 1
		self.matchPlayers[curMsec] = receiverEntityID

		playerEntity.curState = StateDef.Player.Match
		msg = []
		msg.append(MsgDef.CELL2CLIENT_HALL_MSG)
		msg.append(RoomDef.SUBMSG_MATCH_ROOM)
		msg.append(ErrorCodeDef.No)
		IKernel.Instance().sendClientMsg(receiverEntityID, msg)

	def exitRoom(self, receiverEntityID, args):
		playerEntity = KBEngine.entities.get(receiverEntityID)
		if playerEntity.roomID == 0 or playerEntity.curState > StateDef.Player.RoomNoPlayWait:
			# 游戏开始了，不能退出房间了
			msg = []
			msg.append(MsgDef.CELL2CLIENT_HALL_MSG)
			msg.append(RoomDef.SUBMSG_EXIT_ROOM)
			msg.append(ErrorCodeDef.NoInRoom)
			IKernel.Instance().sendClientMsg(receiverEntityID, msg)
			return

		playerEntity.curState = StateDef.Player.Idle
		# 把这个退出的玩家传送到 hall 空间中
		playerEntity.teleport(self.hallEntityID, (0,0,0), (0,0,0))

		msg = []
		msg.append(MsgDef.CELL2CLIENT_HALL_MSG)
		msg.append(RoomDef.SUBMSG_EXIT_ROOM)
		msg.append(ErrorCodeDef.No)
		IKernel.Instance().sendClientMsg(receiverEntityID, msg)

	def setupHeadIcon(self, receiverEntityID, args):
		headIconId = args[2]
		playerEntity = KBEngine.entities.get(receiverEntityID)
		playerEntity.headIconID = headIconId

	def enterRoom(self, receiverEntityID, args):
		roomID = args[2]
		playerEntity = KBEngine.entities.get(receiverEntityID)
		if playerEntity.roomID != 0 and playerEntity.roomID != roomID:
			msg = []
			msg.append(MsgDef.CELL2CLIENT_HALL_MSG)
			msg.append(RoomDef.SUBMSG_ENTER_ROOM)
			msg.append(ErrorCodeDef.AlreadInOtherRoom)
			IKernel.Instance().sendClientMsg(receiverEntityID, msg)
			return

		from logic import ModuleMgr
		roomModule = ModuleMgr.Instance().getModule("RoomModule")
		roomEntity = self.playRooms.get(roomID)
		if roomModule.isFull(roomEntity):
			msg = []
			msg.append(MsgDef.CELL2CLIENT_HALL_MSG)
			msg.append(RoomDef.SUBMSG_ENTER_ROOM)
			msg.append(ErrorCodeDef.RoomFull)
			IKernel.Instance().sendClientMsg(receiverEntityID, msg)
			return

		playerEntity.curState = StateDef.Player.RoomNoPlayWait
		playerEntity.teleport(roomEntity, (0, 0, 0), (0, 0, 0))

		msg = []
		msg.append(MsgDef.CELL2CLIENT_HALL_MSG)
		msg.append(RoomDef.SUBMSG_ENTER_ROOM)
		msg.append(ErrorCodeDef.No)
		IKernel.Instance().sendClientMsg(receiverEntityID, msg)
